#pragma once

#include "log.hpp"
#include "protocol.hpp"
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cctype>

using namespace std;

enum
{
    USAGE_ERR = 10,
    SOCK_ERR,
    READ_ERR,
    CONNECT_ERR
};

class Client
{
public:
    Client(const string &ip, uint16_t port)
        : _sock(-1), _serverIp(ip), _serverPort(port)
    {
    }

    void initClient()
    {
        // 1.创建套接字
        _sock = socket(AF_INET, SOCK_STREAM, 0);
        if (_sock < 0)
        {
            logMessage(FATAL, "创建套接字失败");
            exit(SOCK_ERR);
        }
        logMessage(NORMAL, "创建套接字成功");

        // 2. 这里和UDP一样，还是由操作系统分配端口号，并完成绑定。
    }

    void start()
    {

        // 3.发送链接请求
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(_serverPort);
        server.sin_addr.s_addr = inet_addr(_serverIp.c_str());
        int n = connect(_sock, (struct sockaddr *)&server, sizeof(server));
        if (n != 0)
        {
            logMessage(ERROR, "链接失败");
            exit(CONNECT_ERR);
        }
        logMessage(NORMAL, "链接成功");

        string inbuf; // 客户端接收缓冲区
        while (1)
        {
            // 4.读写
            string message;
            cout << "请输入# ";
            getline(cin, message); // 这样只发送回车会出问题

            Request req = getStr(message);
            string text, send_str;
            req.serialize(&text); // 序列化
            if (!enLength(text, send_str))
                continue;

            send(_sock, send_str.c_str(), send_str.size(), 0);

            string resp_str, resp_text;
            if (!recvPackage(_sock, inbuf, resp_str))
                return;
            if (!deLength(resp_str, resp_text))
                return;

            Response resp;
            resp.deserialize(&resp_text);

            cout << "计算结果：" << endl;
            cout << "flag: " << resp.flag << endl;
            cout << "result: " << resp.result << endl;
        }
    }

    Request getStr(const string &message)
    {
        // 10+10
        int status = 0; // 0:运算符之前  1:碰到运算符  2:运算符之后
        int mes_len = message.size();
        string left, right;
        char op;
        int i = 0;
        // 状态机
        while (i < mes_len)
        {
            switch (status)
            {
            case 0:
            {
                if (!isdigit(message[i]))
                {
                    status = 1;
                }
                else
                    left += message[i++];
            }
            break;
            case 1:
            {
                op = message[i++];
                status = 2;
            }
            break;
            case 2:
                right += message[i++];
                break;
            }
        }
        cout << stoi(left) << " " << stoi(right) << " " << op << endl;
        Request req(stoi(left), stoi(right), op);
        return req;
    }

    ~Client()
    {
    }

private:
    int _sock;
    string _serverIp;
    uint16_t _serverPort;
};